/*************************************************
 Copyright (c) 2019
 All rights reserved.
 File name:     dlt645_port.c
 Description:   DLT645 移植&使用例程文件
 History:
 1. Version:    
    Date:       2019-09-19
    Author:     wangjunjie
    Modify:     
*************************************************/
#include "stdlib.h"

#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"

#include "driver/uart.h"
#include "esp_log.h"
#include "dlt645_port.h"

#define TAG "dlt645 port"

#define RS485_BUF_SIZE        (127)
// Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin
#define RS485_READ_TOUT          (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks

#define PACKET_READ_TICS        (500 / portTICK_PERIOD_MS)
// static SemaphoreHandle_t xSemaphore;
// static int g_uart_num;

/**
 * Name:    dlt645_hw_read
 * Brief:   dlt645 硬件层接收数据
 * Input:
 *  @ctx:   645运行环境
 *  @msg:   接收数据存放地址
 *  @len:   数据最大接收长度 
 * Output:  读取数据的长度
 */
int dlt645_hw_read(dlt645_t *ctx, uint8_t *msg ,uint16_t len)
{
    //实际接收长度
    int read_len = 0;
    read_len = uart_read_bytes(ctx->uart_num, msg, len, PACKET_READ_TICS);
	//ESP_LOGI(TAG, "uart read len %d", read_len);
	//dump(msg, read_len);
    return read_len;
}

/**
 * Name:    dlt645_hw_write
 * Brief:   dlt645 硬件层发送数据
 * Input:
 *  @ctx:   645运行环境
 *  @buf:   待发送数据
 *  @len:   发送长度
 * Output:  实际发送的字节数，错误返回-1
 */
int dlt645_hw_write(dlt645_t *ctx, uint8_t *buf, uint16_t len)
{
	// 清空接收缓存
	// uart_flush_input(ctx->uart_num);
    //串口发送数据
    uint8_t temp[]={0xFE,0xFE,0xFE,0xFE};
    uart_write_bytes(ctx->uart_num,temp,sizeof(temp));
    int ret = uart_write_bytes(ctx->uart_num,buf,len);
    // uart_wait_tx_done(ctx->uart_num, 1000 / portTICK_PERIOD_MS);
    return ret;
}

static bool dlt645_sem_take(dlt645_t *ctx, int timeout)
{
	return xSemaphoreTake( ctx->xSemaphore, timeout);
}

static void dlt645_sem_give(dlt645_t *ctx)
{
	xSemaphoreGive( ctx->xSemaphore );
}

//645采集硬件层修改波特率
int dlt645_port_set_baudrate(dlt645_t *ctx, int baudrate)
{
	uint32_t now_baudrate;
	ESP_ERROR_CHECK(uart_get_baudrate(ctx->uart_num, &now_baudrate));
	if(now_baudrate != baudrate){
	    // Configure UART parameters
	    ESP_ERROR_CHECK(uart_set_baudrate(ctx->uart_num, baudrate));
	}

	return	0;

}
//645采集硬件层修改校验位
int dlt645_port_set_parity(dlt645_t *ctx, int val)
{
	uart_parity_t parity_mode;

	ESP_ERROR_CHECK(uart_get_parity(ctx->uart_num, &parity_mode));
	if(parity_mode != (uart_parity_t)val){
	    // Configure UART parameters
	    ESP_ERROR_CHECK(uart_set_parity(ctx->uart_num, val));
	}
	return	0;

}

/**
 * Name:    dlt645_port_init
 * Brief:   645采集硬件层初始化
 * Input:   None
 * Output:  None
 */
// int dlt645_port_init(dlt645_port_config_t *cfg)
// {
// 	if(NULL == cfg)
// 		return ESP_FAIL;
	
// 	xSemaphore = xSemaphoreCreateMutex();

//     //串口初始化
//     g_uart_num = cfg->uart_num;
//     uart_config_t uart_config = {
//         .baud_rate = cfg->baud_rate,
//         .data_bits = cfg->data_bits,
//         .parity = cfg->parity,
//         .stop_bits = cfg->stop_bits,
//         .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
//         .rx_flow_ctrl_thresh = 122,
//         .source_clk = UART_SCLK_APB,
//     };

//     ESP_LOGI(TAG, "Start RS485 application test and configure UART.");

//     // Install UART driver (we don't need an event queue here)
//     // In this example we don't even use a buffer for sending data.
//     ESP_ERROR_CHECK(uart_driver_install(g_uart_num, RS485_BUF_SIZE * 2, 0, 0, NULL, 0));

//     // Configure UART parameters
//     ESP_ERROR_CHECK(uart_param_config(g_uart_num, &uart_config));

//     ESP_LOGI(TAG, "UART set pins, mode and install driver.");

//     // Set UART pins as per KConfig settings
//     ESP_ERROR_CHECK(uart_set_pin(g_uart_num, cfg->tx_io_num, cfg->rx_io_num, cfg->rts_io_num, UART_PIN_NO_CHANGE));

//     // Set RS485 half duplex mode
//     ESP_ERROR_CHECK(uart_set_mode(g_uart_num, cfg->mode));

// 	if(UART_MODE_RS485_HALF_DUPLEX == cfg->mode){
// 	    // Set read timeout of UART TOUT feature
// 	    ESP_ERROR_CHECK(uart_set_rx_timeout(g_uart_num, RS485_READ_TOUT));
// 	}
//     return  0;
// }

int dlt645_port_create(dlt645_port_config_t *cfg, dlt645_t *dlt645)
{
	if(NULL == cfg || NULL == dlt645)
		return ESP_FAIL;
	
    //串口初始化
    dlt645->uart_num = cfg->uart_num;
    uart_config_t uart_config = {
        .baud_rate = cfg->baud_rate,
        .data_bits = cfg->data_bits,
        .parity = cfg->parity,
        .stop_bits = cfg->stop_bits,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .rx_flow_ctrl_thresh = 122,
        .source_clk = UART_SCLK_APB,
    };

    ESP_LOGI(TAG, "Start RS485 application test and configure UART.");

    // Install UART driver (we don't need an event queue here)
    // In this example we don't even use a buffer for sending data.
    ESP_ERROR_CHECK(uart_driver_install(dlt645->uart_num, RS485_BUF_SIZE * 2, 0, 0, NULL, (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)));

    // Configure UART parameters
    ESP_ERROR_CHECK(uart_param_config(dlt645->uart_num, &uart_config));

    ESP_LOGI(TAG, "UART set pins, mode and install driver.");

    // Set UART pins as per KConfig settings
    ESP_ERROR_CHECK(uart_set_pin(dlt645->uart_num, cfg->tx_io_num, cfg->rx_io_num, cfg->rts_io_num, UART_PIN_NO_CHANGE));

    // Set RS485 half duplex mode
    ESP_ERROR_CHECK(uart_set_mode(dlt645->uart_num, cfg->mode));

	if(UART_MODE_RS485_HALF_DUPLEX == cfg->mode){
	    // Set read timeout of UART TOUT feature
	    ESP_ERROR_CHECK(uart_set_rx_timeout(dlt645->uart_num, RS485_READ_TOUT));
	}

    dlt645->xSemaphore = xSemaphoreCreateMutex();
    dlt645->sem_take = dlt645_sem_take;
    dlt645->sem_give = dlt645_sem_give;
    dlt645->write = dlt645_hw_write;
    dlt645->read = dlt645_hw_read;
    return  0;
}

//645结构体注册
// dlt645_t dlt645 = {
//     {0},
//     0,
//     dlt645_sem_take,
//     dlt645_sem_give,
//     dlt645_hw_write,
//     dlt645_hw_read,
//     NULL};


